import AttributePoolAPI from '@/api/AttributePool';
import {
  Box,
  ClickModal,
  FieldCols,
  FieldEffect,
  FieldTable,
  FormSection,
  mapField,
  useCall,
  useFormValue,
  useReq,
  useTableColumns,
  Icon,
} from '@/components';
import useSessionState from '@/components/hooks/useSessionState';
import { ATTRIBUTE_TYPES_MAP } from '@/constants/attributePool';
import { useWriteObjectOptions } from '@/pages/components';
import { JSONParseFallback, mergeState } from '@/utils';
import { get } from '@/utils/fp';
import { Button, Form, Select, Space, Table } from 'antd';
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { Context } from '.';
import FormulaConfigInput from './FormulaConfigInput';

// 存attributeCode
const attributeListName = ['attributeData', 'additionalAttributes', 'value'];
// 存attributeType=='IN'的attributeCode
const factorAttributesName = ['attributeData', 'factorAttributes', 'value'];

const propsFullwidth = {
  colProps: {
    xs: 24,
    md: 24,
    xl: 16,
  },
  itemProps: {
    labelCol: {
      xs: 8,
      md: 4,
      xl: 4,
    },
  },
};

const propsJsonArrayMulti = {
  itemProps: {
    getValueProps(value) {
      try {
        return {
          value: value?.map((v) => JSON.stringify(v)) ?? [],
        };
      } catch {
        return { value: [] };
      }
    },
    getValueFromEvent(value) {
      try {
        return value?.map(JSONParseFallback) ?? [];
      } catch {
        return [];
      }
    },
  },
};

const propsJsonArraySingle = {
  itemProps: {
    getValueProps(value) {
      try {
        return {
          value: value?.[0] ? JSON.stringify(value[0]) : null,
        };
      } catch {
        return { value: null };
      }
    },
    getValueFromEvent(value) {
      try {
        return [JSONParseFallback(value)].filter(Boolean);
      } catch {
        return [];
      }
    },
  },
};

const merge = (...propList) => propList.reduce((prev = null, next = null) => mergeState(prev, next));

const ATTR_TYPE_PROPS = {
  textarea: merge(propsFullwidth),
  radio: merge(propsJsonArraySingle),
  checkbox: merge(propsJsonArrayMulti),
  select: merge(propsJsonArraySingle),
  'multi-select': merge(propsJsonArrayMulti, { mode: 'multiple' }),
};

const mapFirstProp = (object, propList = []) => {
  const prop = propList?.find((p) => object?.[p] != null);
  return prop && object[prop];
};

const getPattern = (pattern) => {
  if (!pattern) return [];
  let exp;
  try {
    exp = new RegExp(pattern);
  } catch (e) {
    return [];
  }
  return [{ pattern: exp, message: `当前输入不满足属性表达式: "${pattern}"` }];
};

const isAttrNeedsDictionary = (attr) =>
  ['radio', 'checkbox', 'select', 'multi-select'].includes(attr?.attributeImportType);
const isAttrMulti = (attr) => ['checkbox', 'multi-select'].includes(attr?.attributeImportType);

const getAttrDictionaryOptions = (attr) =>
  JSONParseFallback(attr?.attributeDictionary)?.map((v) => ({
    value: JSON.stringify(v),
    label: mapFirstProp(v, ['label', 'name', 'title', 'code', 'id']) ?? `${v}`,
  }));

const getAttrFieldOptions = (attr) => {
  const isDictionary = isAttrNeedsDictionary(attr);
  const isMultiple = isAttrMulti(attr);
  return merge(
    {
      extra: attr?.attributeRemark,
      rules: [...getPattern(attr?.attributeValueSpecs)],
    },
    ATTR_TYPE_PROPS[attr?.attributeImportType] ?? {},
    isDictionary ? { options: getAttrDictionaryOptions(attr) } : {},
    isMultiple ? { initialValue: getAttrDictionaryOptions(attr)?.map((v) => JSONParseFallback(v.value)) } : {},
  );
};

const ATTR_TYPE_COMPONENTS = {
  input: null,
  textarea: 'textarea',
  radio: 'radio-group',
  checkbox: 'checkbox-group',
  select: 'select',
  'multi-select': 'select',
  tree: 'tree',
  cascade: 'cascade',
  formula: FormulaConfigInput,
};

const AttributeListContext = createContext({ attributeList: [], names: [] });

const findAttributeByName = (attrList, name) => {
  return attrList.find((v) => v.id === name);
};

function AttributeSelectModal(props) {
  const { form } = useContext(Context);

  let [selection, onSelect] = useState([]);
  const { attributeList } = useContext(AttributeListContext);
  selection = selection || [];

  const onToggle = useCall((open) => {
    if (open) onSelect(form.getFieldValue(attributeListName));
  });

  const onOk = useCall(() => {
    const names = selection.flatMap((attrId) => {
      const attr = attributeList.find((v) => v.id === attrId);
      if (!attr) return [];
      return [attr.id];
    });

    form.setFields([
      {
        name: attributeListName,
        value: names,
      },
    ]);
  });

  const columns = useTableColumns([
    {
      dataIndex: 'companyName',
      title: '保险公司',
      width: '15%',
    },
    {
      dataIndex: 'attributeCode',
      title: '属性编码',
      width: '15%',
    },
    {
      dataIndex: 'attributeName',
      title: '属性名称',
      width: '40%',
    },
    {
      dataIndex: 'attributeImportType',
      title: '输入类型',
      map: ATTRIBUTE_TYPES_MAP,
    },
  ]);

  const idMapCode = useMemo(() => {
    return attributeList.reduce((ret, item) => {
      ret[item.id] = item.attributeCode;
      return ret;
    }, {});
  }, [attributeList]);

  const selectedCodes = useMemo(() => selection.map((id) => idMapCode[id]), [selection, idMapCode]);

  const content = (
    <>
      <Table
        pagination={false}
        size='small'
        scroll={{ y: 'max(240px, min(720px, calc(100vh - 360px)))' }}
        dataSource={attributeList}
        rowKey='id'
        columns={columns}
        rowSelection={{
          hideSelectAll: true,
          getCheckboxProps(item) {
            return { disabled: !selection.includes(item.id) && selectedCodes.includes(item.attributeCode) };
          },
          selectedRowKeys: selection,
          onChange: onSelect,
        }}
      />
    </>
  );

  return <ClickModal title='选择附加属性' {...props} content={content} onToggle={onToggle} onOk={onOk} />;
}

function useAttributeList() {
  const { form } = useContext(Context);
  const xhr = useReq(AttributePoolAPI.findByPage);
  const [records, setCache] = useSessionState('productfactory.AttributeList');
  const companyCode = useFormValue(form, ['productAddVo', 'productAttrVo', 'companyCode']);
  useEffect(() => {
    xhr.start({ t: {  } });
  }, []);
  let recordsData = xhr.result?.data?.records || null;
  useEffect(() => {
    if (recordsData) setCache(recordsData);
  }, [recordsData]);

  return useMemo(() => {
    if (!records?.length) return []
    if (!companyCode) return records;
    return records.filter(n => ['0', companyCode].includes(n.companyCode));
  }, [records, companyCode])
}

const concatInOrder = (oldArr_, newArr_, getter = []) => {
  let oldArr = oldArr_ || [];
  let newArr = newArr_ || [];
  const newItems = newArr.filter((v) => !oldArr.map(get(getter)).includes(get(getter)(v)));
  const keepItems = oldArr.filter((v) => newArr.map(get(getter)).includes(get(getter)(v)));
  return keepItems.concat(newItems);
};

function AllowCreate(props) {
  const [leadingOptions, setOptions] = useState([]);
  const onSearch = useCall((searchValue) => {
    if (!searchValue && leadingOptions.length) return setOptions([]);
    const isFound = props.options?.some((v) => v.value === searchValue);
    if (isFound && leadingOptions.length) return setOptions([]);
    setOptions([{ value: searchValue, label: searchValue }]);
  });

  useEffect(() => {
    if (leadingOptions.length && props.value !== leadingOptions[0].value) {
      setOptions([]);
    }
  }, [props.value]);

  return (
    <Select
      {...props}
      options={leadingOptions.concat(props.options)}
      showSearch
      onSearch={onSearch}
      dropdownMatchSelectWidth={false}
    />
  );
}

function FactorAttributes({ form, attributes, children }) {
  const [thisForm] = Form.useForm();
  const value = () => form.getFieldValue(factorAttributesName);
  const update = (newValue) => {
    newValue.forEach((item) => {
      item.prop ||= item.code;
      item.label ||= item.name;
    });
    form.setFields([
      {
        name: factorAttributesName,
        value: newValue,
      },
    ]);
  };

  const onToggle = useCall((open) => {
    if (open) thisForm.setFieldsValue({ list: value() });
  });

  const onOk = useCall(async () => {
    const { list } = await thisForm.validateFields();
    update(list);
  });

  const writeObject = useWriteObjectOptions({
    labelKey: (i) => `${i.costName} ${i.costCode}`,
  });

  const fields = [
    ['code', '属性编码', 'plain'],
    ['name', '属性名称', 'plain'],
    ['prop', '因子代码', AllowCreate, { options: writeObject }],
    ['label', '表单名称', null, { required: true }],
  ].map(mapField);

  const content = (
    <>
      <Form form={thisForm} component={false}>
        <FieldTable name='list' form={thisForm} fields={fields} showDragBtn rowKey='id' />
      </Form>
    </>
  );

  useEffect(() => {
    update(concatInOrder(value(), attributes, 'id'));
  }, [attributes]);

  return (
    <>
      <Form.Item name={factorAttributesName} noStyle />
      {attributes?.length > 0 && (
        <ClickModal title='因子属性设置' children={children} content={content} onToggle={onToggle} onOk={onOk} />
      )}
    </>
  );
}

function AttributePoolFields() {
  const { form } = useContext(Context);
  const attributeList = useAttributeList();
  const names = useFormValue(form, attributeListName, (v) => v || []);
  const [fields, factorAttributes] = useMemo(() => {
    const factorAttributes = [];
    const fields = names.flatMap((name) => {
      let attr = findAttributeByName(attributeList, name);
      if (!attr) return [];

      if (attr.attributeType === 'IN') {
        const factor = { id: attr.id, code: attr.attributeCode, name: attr.attributeName };
        factor.prop = factor.code;
        factor.label = factor.name;
        factorAttributes.push(factor);
      }

      const item = mapField([
        ['attributeData', attr.attributeCode, 'value'],
        attr.attributeName,
        ATTR_TYPE_COMPONENTS[attr.attributeImportType],
        getAttrFieldOptions(attr),
      ]);

      return [item];
    });

    return [fields, factorAttributes];
  }, [names, attributeList]);

  if (!attributeList.length) return null;

  return (
    <AttributeListContext.Provider value={{ attributeList, names }}>
      <FieldEffect name={attributeListName} initialValue='' />
      {names?.map((name) => {
        const attr = findAttributeByName(attributeList, name);
        return (
          <FieldEffect
            key={name}
            name={['attributeData', attr.attributeCode, 'attributeType']}
            value={attr?.attributeType}
          />
        );
      })}

      <FormSection title='附加属性'>
        <Box>
          <Space>
            <AttributeSelectModal>
              <Button type='primary'>选择属性</Button>
            </AttributeSelectModal>
            <FactorAttributes form={form} attributes={factorAttributes}>
              <Button>因子</Button>
            </FactorAttributes>
          </Space>
          <Box py={1} />
        </Box>
        <FieldCols form={form} fields={fields} />
      </FormSection>
    </AttributeListContext.Provider>
  );
}

export default AttributePoolFields;
